跳到主要内容
AIDEV CATALOGNOTE

用 Grill 把 Vibe Coding 从“直接写代码”变成工程流程

基于 Matt Pocock(AI Hero)的 7 节 AI Skills 邮件课程及对应 Skill 指南整理。

一、先理解核心:不要把 Vibe Coding 等同于“让 AI 写代码”

Vibe Coding 真正需要解决的不是生成速度,而是以下五个工程问题:

  1. 方向是否明确:需求模糊时,Agent 依然会产出代码,但很可能是在快速实现错误答案。
  2. 未知是否被验证:交互、状态模型和第三方能力,有些问题靠讨论无法确定。
  3. 任务是否适合上下文窗口:Agent 一次承担太多内容,后半段往往会遗忘约束。
  4. 执行是否可控制:后台 Agent 必须隔离、可观察、可停止、可审查。
  5. 经验是否能进入下一轮:只修当前 Diff,不改善文档、验证和架构,下次仍会犯同样的错。

因此,完整工作流不是“一句话需求 → 生成代码”,而是:

澄清 → 必要时原型验证 → 固化决策 → 拆分任务 → 隔离执行 → 双轴审查 → 改进工作系统

这套方法的目标也不只是完成一个功能,而是让每轮执行结束后同时得到:

  • 可工作的代码;
  • 更清楚的业务语言与决策记录;
  • 更可靠的验证方法;
  • 更适合后续 Agent 理解的代码结构。

二、先判断任务规模,不要每次跑完整流程

路径 A:小型、明确任务

适合:文案调整、样式修复、已定位 Bug、简单接口字段变更。

读取相关代码 → 明确验收条件 → 实现 → 测试 → 审查 Diff

不需要 Spec、Tickets 或 Prototype。完整流程会增加成本,反而可能在多次转述中发生语义漂移。

路径 B:中型功能,方向基本明确

适合:单页面功能、局部重构、一个上下文窗口内可以完成的需求。

Grill → Implement → Code Review

如果讨论中出现无法仅靠语言解决的问题,再临时进入 Prototype 分支。

路径 C:跨会话工作

这里必须区分“实现跨会话”和“规划本身跨会话”:

规划能在一个会话完成,只有实现跨会话:
Grill → Prototype(按需)→ Spec → Tickets → 逐票 Implement → Review

连规划和决策本身都无法装进一个会话,且路线仍然模糊:
Wayfinder → 逐个解决 Decision Ticket → Spec → Tickets → 逐票 Implement → Review

wayfinder 不是所有大功能的默认入口。只有决策工作本身需要多个会话时才使用;如果方向已经清楚,只是代码量大,直接进入 Spec 和 Tickets。

路径 D:存量项目治理

适合:老项目、架构腐化、Agent 经常走错目录或重复造轮子。

架构扫描 → 选一个高收益问题 → Grill → Spec/Tickets → Refactor → Review → 更新长期文档

一个简单判断标准:

当前状态下一步
一个会话内可以澄清的需求Grill with Docs
规划本身跨多个会话,路线仍然模糊Wayfinder
有一个靠讨论无法回答的问题Prototype
已决定,且一次会话能完成直接 Implement
已决定,但要跨多个会话Spec → Tickets
已经有 DiffCode Review
整个项目持续让 Agent 迷路架构扫描与长期文档治理

三、先学会调用:这些指令到底敲在哪里

安装命令在终端执行,Skill 指令在 Coding Agent 的聊天框执行,两者不要混淆。

3.1 首次安装

在项目根目录的终端执行:

npx skills@latest add mattpocock/skills

安装时至少选择:

setup-matt-pocock-skills
grill-with-docs
grilling
domain-modeling
wayfinder
prototype
handoff
to-spec
to-tickets
implement
code-review
improve-codebase-architecture

然后在 Agent 聊天框中初始化当前仓库:

/setup-matt-pocock-skills

Matt 的文档统一使用 /skill-name 表示调用。不同 Coding Agent 的显式调用语法可能不同;如果客户端没有对应的斜杠命令,直接点名 Skill 和任务即可。不要假定所有 Codex 客户端都支持同一种 $skill-name 语法。

/grill-with-docs 规划用户退款功能

使用 grill-with-docs skill 规划用户退款功能

如果客户端没有斜杠命令补全,直接点名 Skill 是最稳妥的写法。

3.2 Skill 指令的通用结构

不要只输入 Skill 名称。推荐写成:

/<skill> <处理对象>

目标:这一步想得到什么。
输入:应该读取哪些代码、文档、Issue 或当前对话。
边界:这一步不能做什么。
输出:结束时必须返回什么。

例如:

/grill-with-docs 规划退款功能。

目标:确认状态流转、幂等规则、权限和验收标准。
输入:先读取订单、支付、退款相关代码和现有文档。
边界:暂时不要实现,不要生成 Spec。
输出:分轮向我提问,并列出最终确认项和未决项。

3.3 四条路径的实际操作

路径 A:小型、明确任务

在当前会话直接执行:

/implement 当前任务已经明确,计划就在当前对话中:

1. 将登录按钮文案改为“立即登录”
2. 禁用颜色复用现有主题变量
3. 不修改登录流程
4. 完成后运行相关测试和类型检查

提交后,在干净的新会话中执行:

/code-review main

完整顺序:

/implement <明确任务>
→ 新会话
/code-review <分支起点>

极小的文案或样式修改也可以直接描述任务,不必强制调用 Skill。

路径 B:中型功能

先在当前会话执行:

/grill-with-docs 给商品列表增加价格区间筛选。

请先读取商品列表、查询参数、接口封装和现有筛选组件。
分轮确认筛选交互、URL 状态、默认值、边界情况和验收标准。
能从代码确认的内容不要问我,暂时不要实现。

回答完全部问题后,不清空当前上下文,继续执行:

/implement 使用刚才在当前对话中确认的方案直接实现。

实现完成后开启新会话:

/code-review main

完整顺序:

/grill-with-docs <功能>
→ 回答分轮问题
/implement 使用当前对话中的方案
→ 新会话
/code-review <分支起点>

路径 C:跨会话工作

先判断跨会话的是“实现”还是“规划”。

如果需求能在当前会话讨论清楚,只是实现量较大,仍然从 /grill-with-docs 开始:

在规划会话中依次执行:

/grill-with-docs 规划完整退款系统。
请先读取相关代码,分轮确认业务规则、状态、权限、异常恢复、幂等和验收标准。
暂时不要实现。

遇到一个无法仅靠讨论确认的问题时,才进入原型支线:

/handoff 为“退款状态机原型”生成交接文档,只保留原型所需上下文。

在新的原型会话中:

读取这份 handoff 文件,然后执行:

/prototype 验证重复申请、超时回调和人工审核并发发生时,
状态机是否可能产生重复退款。

只回答这个问题,不接真实接口,不修改生产代码。

把原型结论带回原规划会话,然后执行:

/to-spec 将当前对话已经确认的方案整理成 Spec。
不要发明未讨论过的需求,保留原型结论、测试接缝和范围外事项。

不要清空上下文,紧接着执行:

/to-tickets 把刚生成的 Spec 拆成 Agent 可独立完成的 Tickets。
每张 Ticket 必须能独立演示、适合一个上下文窗口,并标明依赖和验证命令。
发布前先把拆分方案给我确认。

确认 Ticket 后,每张 Ticket 使用一个干净会话:

/implement https://github.com/owner/repo/issues/42

开始前先复述标题、范围和验收标准,一次只实现这一张 Ticket。

全部完成后再做总审查:

/code-review main

完整顺序:

/grill-with-docs <大型功能>
→ 必要时 /handoff + /prototype
/to-spec
/to-tickets
→ 每张 Ticket 新会话:/implement <完整 Issue URL>
→ 最终新会话:/code-review <分支起点>

如果连需要作出哪些决策都不完全清楚,规划本身需要多个会话,则改用:

/wayfinder 描绘完整退款系统的决策地图。

目标:明确最终要到达的状态,并找出在进入实现前必须解决的决策。
边界:只规划和解决决策,不编写产品代码。
输出:建立决策地图、Decision Tickets、依赖关系和当前 Frontier。

随后在独立会话中逐个解决开放且未阻塞的 Decision Ticket。它们的产物是“决定”,不是实现代码。地图清空后执行:

/to-spec <完整的 Wayfinder Map 引用>
/to-tickets
→ 每张实现 Ticket 新会话:/implement <完整 Issue URL>
→ 最终新会话:/code-review <分支起点>

路径 D:存量项目治理

先扫描,不直接重构:

/improve-codebase-architecture

扫描当前代码库,寻找值得加深模块边界的架构问题。
先只生成候选报告,不修改代码,也不要直接选择第一个候选。
优先分析近期频繁修改和反复出错的区域。

看完报告后选择一个候选:

选择候选 2。针对它开始 Grill,确认目标边界、迁移约束、
需要保留的接口和测试接缝。仍然不要修改代码。

决策完成后回到主流程:

/to-spec
/to-tickets
→ 每张 Ticket:/implement <完整 Issue URL>
→ /code-review <分支起点>

四、阶段 1:Grill with Docs——有状态的领域建模访谈

4.1 它不只是澄清需求

grill-with-docs 是一个面向代码仓库、限定在单个规划会话内的有状态访谈。它同时完成两件事:

  1. 通过 grilling 的决策树与 Frontier 机制,让你和 Agent 对方案形成共同理解;
  2. 通过 domain-modeling 在访谈过程中持续维护统一领域语言和重要决策记录。

它与普通 grill-me 最关键的区别是:结果不只留在对话中,还会在磁盘上留下经过筛选的长期知识。

默认行为既不是一次只问一个问题,也不是把所有问题一次抛完。每轮会提出当前 Frontier 上已经满足前置条件、彼此不依赖的问题;你的回答会解锁下一轮问题。问题总数不设固定上限,如果范围不断膨胀,应主动收窄任务或要求结束。

需要澄清四类内容:

  • 目标:用户最终获得什么变化?
  • 边界:哪些内容明确不做?
  • 约束:兼容性、技术栈、上线时间、性能、安全要求是什么?
  • 不稳定决策:哪些假设一旦错误,会导致大量返工?

可直接使用的开场提示:

请先不要实现。阅读与该需求相关的代码和文档,然后分轮向我提问,
帮助我明确目标、范围、约束、验收标准和仍未解决的关键决策。

能从仓库确认的信息不要问我。按照决策依赖分轮提问,
每个问题给出推荐答案及取舍。发现术语冲突或现有实现与需求矛盾时明确指出。

如果你个人更喜欢一次回答一个问题,可以在 AGENTS.mdCLAUDE.md 中配置:

When grilling, ask one question at a time.

这属于个人交互偏好,不是 Skill 默认机制。

4.2 Stateful:访谈过程中实时写回仓库

写文件不是会话结束后的人工整理步骤,而是 Skill 在访谈过程中自动执行的核心行为:

  • 稳定的业务术语:写入 CONTEXT.md 或项目已有的领域文档。
  • 难以逆转、令人意外且存在真实取舍的决定:写入 docs/adr/
  • 只服务当前功能的细节:进入 Spec 或当前任务,不写入全局说明。
  • 临时猜测、推导过程:留在会话中,不污染仓库。

单 Context 仓库默认使用根目录的 CONTEXT.mddocs/adr/。如果根目录存在 CONTEXT-MAP.md 并将项目标记为多 Context 仓库,术语应写入对应上下文自己的 CONTEXT.md

CONTEXT.md 只保存项目词汇和紧凑定义,不应混入功能 Spec、实现细节或临时笔记。这也能避免 AGENTS.mdCLAUDE.md 变成所有历史问题的堆积场。

4.3 人负责决策和控制范围

Agent 负责发现事实、提出问题和推荐方案,但不能替你作出产品与设计决定。使用者需要主动:

  • 质疑问题的前提和推荐答案;
  • 阻止问题扩展到当前目标之外;
  • 要求重新打开被错误关闭的决策分支;
  • 识别需要 Prototype 的高保真问题;
  • 判断什么时候已经达到共同理解并允许结束。

连续回答“同意”并不等于有效 Grill。规划阶段更依赖模型的参数化知识来发现你没有想到的问题,因此值得使用能力较强的模型;进入上下文充分的实现阶段后,才更适合考虑较小模型。

4.4 完成标准与故障信号

  • CONTEXT.md 在访谈过程中随着术语确认逐条变化,而不是结束时一次性生成。
  • CONTEXT.md 保持为纯词汇表,没有 Spec 和实现细节。
  • Agent 使用项目自己的业务名词,而不是泛化命名。
  • “不做什么”已经明确。
  • 每个关键决策都有确定答案,或被标记为需要 Prototype。
  • 代码中能确认的内容没有被反问给用户。
  • 结束前 Agent 会要求你确认双方已经形成共同理解,而不是自动开始实现。

一次会话只让词汇表更清晰、没有生成任何 ADR,完全可能是正常结果;大多数功能决定不满足 ADR 的三个门槛。

如果出现下面情况,先检查 Skill 是否正确加载,而不是继续追加提示词:

  • 所有问题一次性抛出;
  • 问题没有推荐答案;
  • 全程不提 CONTEXT.md
  • 访谈正常,但没有任何领域文档变化。

可直接要求:

停止当前 Grill。说明本次实际加载了哪些 Skills,
并确认 grilling 和 domain-modeling 是否都已加载。

五、阶段 2:Prototype——用一次性代码回答一个问题

5.1 什么时候需要原型

只有满足下面条件才值得原型化:

存在一个具体、重要的问题,而且仅靠继续讨论无法可靠回答。

典型问题:

  • 页面采用抽屉还是分步流程,哪种信息层级更清楚?
  • 状态机在返回、刷新和重复回调时是否正确?
  • 长连接断线重连是否会造成事件重复?
  • 某个 SDK 在目标平台上是否真的支持所需能力?

如果问题是“已经实现的功能为什么坏了”,应该诊断 Bug,而不是做 Prototype。

5.2 原型的约束

原型只为学习服务,因此通常不要添加:

  • 完整错误处理;
  • 持久化数据库;
  • 预防未来需求的抽象;
  • 生产级测试和兼容层;
  • 与核心问题无关的 UI 美化。

推荐模板:

# Prototype Question

## 要回答的问题
在用户重复提交并返回上一页时,当前状态机是否会产生两个有效订单?

## 成功标准
- 可以复现正常、重复提交、请求超时三个场景
- 每一步显示完整状态
- 产品或开发无需阅读代码即可操作

## 明确不做
- 不接真实支付接口
- 不实现正式 UI
- 不写入生产数据库

5.3 两类原型

逻辑或状态原型:建议做成单个可打开的 HTML;核心逻辑保持为纯函数、Reducer 或状态机,页面显示当前完整状态并提供场景化操作按钮。

UI 原型:一次至少展示多个结构明显不同的方案。变化应体现在信息架构和交互,而不只是颜色、圆角和文案。尽量放入真实页面壳和接近真实的数据密度中。

5.4 如何保存原型结论

原型代码不合并进主分支,但也不必彻底删除:

prototype/<question-name> 分支:保存可重新运行的证据
正式任务或 ADR:保存问题、结论和原型分支链接
main:只接收基于结论重新实现的生产代码

如果原型超过一天还没有回答问题,通常说明问题范围太大,需要继续切小。


六、阶段 3:Handoff——只在上下文真的需要移动时使用

Handoff 不是普通总结,也不是所有阶段结束后的固定动作。它的价值是可移植性

适合四种情况:

  1. 从 Claude Code 切换到 Codex、Cursor 等另一套工具;
  2. 移动到新的目录或原型仓库;
  3. 把工作交给同事;
  4. 保留当前主会话,同时把支线问题交给另一个执行者。

同一工具、同一目录、同一任务继续工作时,优先继续会话或做上下文压缩,不必 Handoff。

Handoff 文档模板

# Handoff:验证订单状态机

## 目标
通过最小原型确认重复提交和超时恢复时的状态转移。

## 已确认事实
- 当前 Web 端入口:`src/pages/order/...`
- 服务端以 idempotencyKey 去重

## 尚未确认
- 客户端返回上一页后是否复用旧 key

## 本次任务
只实现可操作的状态机原型,不修改生产代码。

## 约束
- 不连接真实接口
- 不引入新的状态管理库

## 相关资料
- Spec:`docs/specs/order-submit.md`
- ADR:`docs/adr/003-idempotency.md`

## 完成后返回
- 一句话结论
- 能复现结论的操作步骤
- 原型分支或文件路径

已经存在于 Spec、ADR、Issue 和代码中的内容只引用路径,不要重复复制,否则会产生两个可能漂移的事实源。交接前还要检查:推测是否被误写成事实,文件中是否含 Token、密码或用户隐私。


七、阶段 4:Spec——记录已经作出的决定

7.1 什么时候写 Spec

Spec 的唯一硬触发条件是:

方向已经确定,但实现将跨越多个 Agent 会话,需要让决定在上下文结束后继续存在。

如果任务一次会话能完成,直接实现即可。每个小修改都写 Spec,不仅浪费 Token,还会增加一次模型转述造成的漂移。

7.2 Spec 不应该继续发明需求

to-spec 的输入来自:

  • 刚完成的澄清对话;
  • 仓库代码;
  • CONTEXT.md
  • ADR;
  • 原型验证结论。

它的职责是合成已有决定,而不是重新采访或自动补全产品需求。Spec 中出现一个从未讨论过的确定性要求,就是缺陷。

7.3 推荐 Spec 模板

# 功能名称

## 背景与目标
为什么做;完成后用户或系统获得什么变化。

## 已确认决策
- 决策及原因
- 原型验证结论与引用

## 范围
- 本次包含
- 本次明确不包含

## 业务规则与状态
- 正常路径
- 边界状态
- 失败和恢复路径

## 现有系统接缝
- 从哪个入口触发
- 通过哪个接口或模块完成
- 尽量复用哪些现有边界

## 验收标准
- 可观察、可测试的结果
- 每项都能追踪到已确认需求

## 风险与发布
- 兼容性、迁移、灰度、回滚和监控

7.4 先确认测试接缝

写长篇说明前,先确认功能在哪个边界上被验证。例如:

  • 纯函数或 Reducer;
  • API handler;
  • 页面级集成测试;
  • 跨端通信协议;
  • H5 ↔ Native JSBridge 协议。

优先选择现有且最高层的稳定接缝,数量越少越好。重点人工审查 Out of Scope 和测试接缝,因为这里出错的返工成本最高。


八、阶段 5:Tickets——按可演示的垂直切片拆分

8.1 不要按技术层拆

错误示例:

  1. 创建数据库表;
  2. 实现全部 API;
  3. 实现全部页面;
  4. 最后补测试。

这些 Ticket 单独结束时没有完整可用结果,验收标准互相跨越,集成风险被推到最后。

推荐按 Tracer Bullet 拆分:每张 Ticket 是穿过必要层次的一条窄路径,可以独立运行、演示和验收。

示例:梦境记录功能可以拆成:

  1. 用户创建一条纯文本梦境并在列表看到它;
  2. 用户编辑已有梦境,刷新后内容仍存在;
  3. 用户请求 AI 解析并看到加载、成功与失败状态;
  4. 用户从解析结果生成分享卡片。

每张票可能同时涉及 Schema、API、UI 和测试,但都能独立说明“完成后可以演示什么”。

8.2 Ticket 模板

# 用户可创建并查看纯文本梦境

## 价值
完成后用户可以保存梦境,并立即在历史列表中看到。

## 范围
- 表单输入与校验
- 创建接口
- 列表展示
- 对应测试

## 不包含
- AI 解析
- 图片上传
- 分享卡片

## 验收标准
- 空内容无法提交
- 创建成功后列表立即出现记录
- 刷新页面后记录仍存在
- API 失败时保留输入并显示错误

## Demo Path
登录 → 新建梦境 → 输入内容 → 保存 → 在列表中打开

## 依赖
无 / Blocked by #xx

## 验证命令
pnpm lint
pnpm test -- dream-create
pnpm build

8.3 大范围重构的例外

跨全项目的字段或公共类型迁移很难拆成正常垂直切片,可以使用 Expand–Migrate–Contract:

  1. Expand:增加新接口,同时保留旧接口,CI 仍然通过;
  2. Migrate:按包、目录或业务域分批迁移调用方;
  3. Contract:所有调用方迁移后删除旧接口。

如果某张 Ticket 完成后回答不了“现在可以演示什么”,它多半仍是横向切片。


九、阶段 6:安全执行——让 Agent 自主,但不要失控

无论使用 Codex Worktree、Docker、Podman、云沙箱还是 Sandcastle,后台执行都至少需要:

  • 明确且足够小的任务范围;
  • 隔离分支或 Worktree;
  • 可见日志;
  • 自动验证命令;
  • 以 Commit 或 Diff 返回结果;
  • 不自动发布、不自动改生产环境;
  • 第二轮独立审查的入口。

9.1 最小执行提示模板

实现 Ticket #12,只处理 Ticket 定义的范围。

开始前:
1. 阅读 Ticket、相关 Spec、项目指令文件(`AGENTS.md` / `CLAUDE.md`)和涉及目录的代码。
2. 复述验收标准与验证命令;如果信息冲突,停止并报告。

实现时:
1. 优先复用现有结构,不顺手重构无关区域。
2. 每完成一个可验证节点就运行最小测试。
3. 不修改生产配置,不提交密钥,不执行发布操作。

结束时:
1. 运行 lint、测试和构建。
2. 汇报改动、验证结果、残余风险和未完成项。
3. 生成一个范围清晰的提交,等待审查。

9.2 Sandcastle 可选方案

Sandcastle 是 TypeScript 编排库,可把 Agent 放入 Docker、Podman 或 Vercel 沙箱,管理分支并回收提交。快速开始:

npm install --save-dev @ai-hero/sandcastle
npx @ai-hero/sandcastle init
npx tsx .sandcastle/main.ts

典型配置:

import { run, codex } from "@ai-hero/sandcastle";
import { docker } from "@ai-hero/sandcastle/sandboxes/docker";

const result = await run({
agent: codex("gpt-5.4"),
sandbox: docker(),
promptFile: ".sandcastle/prompt.md",
branchStrategy: {
type: "branch",
branch: "agent/dream-create",
},
maxIterations: 3,
});

console.log(result.commits);

这只是可选的执行基础设施。独立 Git 分支或 Worktree 加人工审查通常已经够用;需要多个 AFK Agent、统一日志或实现—审查流水线时,再引入 Sandcastle。


十、阶段 7:Code Review——分开回答两个问题

审查必须明确区分两个轴:

审查轴核心问题主要依据
Standards代码写得对不对?项目规范、既有模式、架构约束、代码异味
Spec做的是不是正确的东西?Spec、Ticket、验收标准、明确的范围外事项

一份符合所有代码规范、却实现错需求的代码,Standards 可以通过,但 Spec 必须失败;反过来也一样。不要用一个综合分数让其中一项掩盖另一项。

10.1 审查提示模板

审查当前分支相对 main 的 Diff,不要直接修改代码。

分别输出两部分:

1. Standards Review
- 对照仓库规范与现有实现模式
- 检查不必要重复、错误抽象、跨层耦合和维护风险
- 跳过已经由 Linter 可靠覆盖的问题

2. Spec Review
- 对照 Ticket/Spec 的每项验收标准
- 找出遗漏、部分实现、实现错误和范围膨胀

每条发现必须包含:严重级别、证据位置、违反的依据、影响和最小修复建议。
如果没有证据,不要提出推测性问题。

最佳实践是让一个干净的新会话审查,避免编写代码的同一上下文替自己确认。每张 Ticket 完成后审查一次,整个功能合并前再相对分支起点做一次全局审查。

Agent 的审查结论仍然只是待验证的假设。执行修复前,要核对它引用的代码和需求依据是否真实存在。


十一、阶段 8:让一次错误改善下一次运行

Agent 出现可避免错误时,不要只问“换更强模型是否能解决”,而要做一次根因分类:

错误类型应改进的位置
误解业务词语CONTEXT.md 或领域文档
忘记长期稳定规则最小化后的 AGENTS.mdCLAUDE.md 或技术 Skill
漏掉当前需求Spec 或 Ticket
不知道如何确认成功验收标准、测试或 CI
多次在同一模块绕路模块接口、目录边界或架构
仅本次偶发推理错误修复当前代码,不急着增加规则

长期规则只有在满足以下条件时才值得进入 AGENTS.mdCLAUDE.md 或 Skill:

  • 下个月仍然成立;
  • 会影响多项任务;
  • 仓库本身无法轻易推断;
  • 不与 Linter、类型系统或已有文档重复;
  • 能写成明确、可操作、可验证的规则。

否则,规则越积越多会消耗上下文,并产生冲突和过时约束。


十二、完整 Demo:从模糊需求到完成审查

下面以“为任务管理应用增加到期提醒”为例,完整走一次大型任务流程。重点不是功能本身,而是观察每个 Skill 如何衔接。

12.1 起点:只有一句模糊需求

原始想法:

给任务增加提醒功能。

不要直接让 Agent 开发,先执行:

/grill-with-docs 给任务管理应用增加到期提醒。

先读取任务模型、创建和编辑流程、通知能力及现有文档。
通过分轮问题帮我确认提醒的触发规则、时区、重复任务、修改任务后的处理、
权限、失败恢复和验收标准。暂时不要实现。

12.2 Grill 的示例交互

Agent 第一轮可能问:

1. 提醒时间由用户单独设置,还是根据截止时间自动计算?
A. 单独设置(推荐):灵活,但多一个输入项
B. 截止前固定 30 分钟:简单,但不够灵活
C. 同时支持:体验完整,但首版范围更大

2. 用户修改截止时间时,已有提醒如何处理?
A. 保持相对间隔自动移动(推荐)
B. 保持原绝对时间
C. 删除并要求重新设置

用户回答:

1 选 A,提醒是独立时间,但必须早于截止时间。
2 选 B,提醒保持原绝对时间;如果新的截止时间早于提醒时间,要求用户重新选择。
首版不支持重复任务,也不做短信,只做应用内通知。

继续回答后,最终应得到类似结论:

已确认:
- 每个任务最多一个提醒
- 提醒使用用户选择的绝对时间
- 数据统一存 UTC,展示使用用户时区
- 修改截止时间造成提醒无效时阻止保存
- 只做应用内通知

范围外:
- 重复任务
- 邮件和短信
- 多次提醒

未决问题:
- 跨夏令时切换时,用户看到的本地时间是否符合预期

12.3 对未知问题做 Prototype

夏令时问题难以靠口头确认,于是创建支线:

/handoff 为“提醒时间与夏令时原型”生成交接文档。
只保留时间存储、展示和修改所需的上下文。

在新会话执行:

/prototype 验证提醒跨越夏令时切换时的行为。

唯一问题:用户选择“每天当地时间 09:00”的语义,
与存储一个绝对 UTC 时间的结果是否一致?

提供三个可操作场景并显示本地时间、时区和 UTC 值。
不接数据库,不实现正式 UI。

原型给出结论:一次性提醒存绝对 UTC 即可;“每天 09:00”属于重复提醒语义,本期不做。把这一结论返回规划会话。

12.4 生成 Spec

/to-spec 将当前对话确认的到期提醒方案写成 Spec。

必须包括:
- 一次性提醒的数据语义
- UTC 存储与本地展示
- 修改截止时间时的校验
- 应用内通知的失败处理
- 测试接缝
- 明确的范围外事项
- prototype/reminder-dst 原型结论

不得加入重复提醒、短信或邮件通知。

人工重点检查:

  • Spec 是否把“每个任务最多一个提醒”写成了验收条件;
  • 是否擅自增加了重复提醒;
  • 测试接缝是否落在现有任务服务和通知调度器边界;
  • Out of Scope 是否完整。

12.5 拆 Tickets

/to-tickets 把提醒功能 Spec 拆成垂直 Tickets。

每张 Ticket 都必须:
- 能独立演示
- 同时包含所需的数据、逻辑、界面和测试
- 适合一个新会话完成
- 写明 Demo Path、依赖和验证命令

发布前先展示拆分方案。

合理的拆分可能是:

  1. 用户创建任务时可以设置一个提醒,并在详情页看到;
  2. 用户编辑或删除提醒,刷新后结果保持;
  3. 到达提醒时间后用户收到应用内通知;
  4. 修改截止时间导致提醒无效时阻止保存并给出提示;
  5. 调度失败能够重试并留下可观察记录。

错误拆法则是:先建表、再写接口、再写页面、最后补测试。因为每张票单独完成时都没有可演示能力。

12.6 实现第一张 Ticket

新建目标分支或 Worktree,然后开启干净会话:

/implement https://github.com/example/tasks/issues/101

开始前先确认:
- Ticket 标题
- 范围和范围外
- 测试接缝
- 验证命令

一次只实现 #101,不顺便实现后续通知调度。

Agent 应当读取 Ticket,按确认的接缝编写测试,反复运行局部测试和类型检查,最后运行完整测试并产生一个范围清楚的提交。

完成后人工检查、关闭 Ticket,再用新的会话执行下一张:

/implement https://github.com/example/tasks/issues/102

12.7 独立审查

每张 Ticket 可以单独审查。所有 Ticket 完成后,再开一个不含实现过程的新会话:

/code-review main

审查当前分支相对 main 的全部改动。
分别报告 Standards 和 Spec 两个维度,不要把它们合并评分。
每条发现必须引用具体代码和对应规范或 Spec 条目。
只审查,不直接修改。

如果审查发现“修改截止时间后没有验证提醒时间”,这是 Spec 符合度问题;如果功能正确但绕过项目既有任务服务直接访问数据库,则是 Standards 问题。

12.8 把错误反馈到正确位置

假设 Agent 把所有本地时间直接写入数据库,需要区分:

  • Spec 已明确 UTC,而 Agent 漏做:修复代码和当前 Ticket。
  • Spec 没有写清时间语义:修复 Spec/Ticket 生成流程。
  • 项目多个功能都反复混用时间:在长期文档中补充稳定时间约定,或封装统一时间模块。

最终闭环不是“这次修好了”,而是“下一次更难犯同类错误”。


十三、一页执行清单

开始前

  • 任务目标是否一句话说得清?
  • 范围外事项是否明确?
  • Agent 是否先读取了相关代码?
  • 是否存在只能通过运行或看见才能回答的问题?

规划时

  • 一次会话是否足以完成?足够则跳过 Spec/Tickets。
  • Spec 是否只记录已作出的决定?
  • 测试接缝是否明确?
  • 每张 Ticket 是否能独立演示?
  • 依赖关系是否真实而非人为串行?

执行时

  • 是否在隔离分支、Worktree 或沙箱中?
  • 是否限制修改范围和权限?
  • 日志和验证结果是否可见?
  • 是否禁止自动部署和生产环境变更?

审查后

  • Standards 和 Spec 是否分别检查?
  • 审查发现是否都有代码或文档证据?
  • 错误来自代码、任务、文档、验证还是架构?
  • 哪些经验值得长期保存,哪些只应留在本次任务?

十四、最终原则

  1. 先减少不确定性,再提高生成速度。
  2. Prototype 只回答一个问题,不负责变成产品。
  3. Spec 是已确认决策的快照,不是让 AI 发明需求的模板。
  4. Ticket 按可独立演示的垂直能力拆分。
  5. 自主执行必须以隔离、可观察和可审查为前提。
  6. 代码规范与需求符合度必须分开审查。
  7. 一次 Agent 错误,应优先改善系统,而不是无限堆规则或直接换模型。
  8. 工作流按任务规模裁剪;能简单解决的问题,不要仪式化。
  9. Grill 辅助工程师作出决定,不替代工程师;人必须主动控制范围和确认结论。
  10. 实现跨会话使用 Spec/Tickets,规划本身跨会话且路线模糊才使用 Wayfinder。

参考资料

注:本文不是逐字翻译,而是基于邮件课程与下钻文档提炼、纠偏后形成的工程实践版本。